using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using AutoUpdateEngine.Sstc.UpdateService;
using AutoUpdateEngine.Operations;
using AutoUpdateEngine.FileSystem;
using AutoUpdateEngine.Xml;

namespace AutoUpdateEngine
{
    /// <summary>
    /// the actual executor of the update operations
    /// </summary>
    public class Updater
    {
        /// <summary>
        /// initial updater with the default working directory used by update engine
        /// </summary>
        /// <param name="defaultWorkingDirectory"></param>
        public Updater(string defaultWorkingDirectory)
        {
            us = new UpdateService();
            this.defaultWorkingDirectory = defaultWorkingDirectory;
        }
        /// <summary>
        /// execute the update operations
        /// </summary>
        public void Update()
        {
            try
            {
                //download update manifest to a temp file on local disks
                string updateManifestFile = GetUpdateManifest();

                //pase the update manifest into a set of update operations
                ops = PaseIntoUpdateOperations(updateManifestFile);

                //display the number of items to be updated
                int count = ops.Count;
                report(string.Format("there are {0} items to be updated", count));

                fileAccesser = new DefaultFileAccesser(defaultWorkingDirectory);
                int index = 0;
                foreach (IOperation op in ops)
                {
                    op.AttachFileAccesser(fileAccesser);
                    try
                    {
                        index++;                        
                        op.Do();
                        report(string.Format("\t[Success]{0} {1} <{2}/{3}>", op.Type, op.AppPart.FileName, index, count));
                    }
                    catch (Exception opex)
                    {
                        report(string.Format("\t[Exception]{0} {1} :{2}",op.Type,op.AppPart.FileName,opex.Message));
                    }                   

                }
                //delete update manifest downloaded
                File.Delete(updateManifestFile);
            }
            catch (Exception ex)
            {
                report(ex.Message);
            }
        }
        /// <summary>
        /// a delegate used to send msg back to GUI
        /// </summary>
        public ReportProgress Report
        {
            get
            {
                return report;
            }
            set
            {
                report = value;
            }
        }
        /// <summary>
        /// pase the update manifest into a set of update operations
        /// </summary>
        /// <param name="updateManifestFile"></param>
        /// <returns></returns>
        private IList<IOperation> PaseIntoUpdateOperations(string updateManifestFile)
        {
            XMLPaser xmlPaser = new XMLPaser(updateManifestFile);
            return xmlPaser.GetOperations();
        }
        /// <summary>
        /// download update manifest to a temp file on local disks
        /// </summary>
        /// <returns>name of the file which contains the content of the update manifest </returns>
        private string GetUpdateManifest()
        {
            string manifest = us.GetUpdateManifest();
            string tmpFile = Path.GetTempFileName();
            File.WriteAllText(tmpFile, manifest);
            return tmpFile;
        }

        UpdateService us;
        IList<IOperation> ops;
        IFileAccesser fileAccesser;
        string defaultWorkingDirectory;
        ReportProgress report;
    }

    /// <summary>
    /// send some messages back to GUI
    /// </summary>
    /// <param name="msg"></param>
    public delegate void ReportProgress(string msg);
}
